package com.hutu.picture.infrastructure.config;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.scheduling.annotation.AsyncConfigurer;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.Executor;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;

/**
 * 异步线程开启
 */
@Configuration
@EnableAsync
public class ThreadPoolConfig implements AsyncConfigurer {
    @Override
    public Executor getAsyncExecutor() {
        return myExecutor();
    }

    @Bean("my-myExecutor")
    @Primary
    public ThreadPoolTaskExecutor myExecutor() {
        // spring所管理的,赋予了优雅停机 ExecutorConfigurationSupport -> DisposableBean
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        // 优雅停机 当spring关闭时,调用destroy时会调用shutdown方法
        executor.setWaitForTasksToCompleteOnShutdown(true); 
        executor.setCorePoolSize(10);
        executor.setMaxPoolSize(10);
        executor.setQueueCapacity(200);
        executor.setThreadNamePrefix("myproject-executor-");
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());//满了调用线程执行，认为重要任务
        // 添加异常处理,因为如果添加,出现异常时会被吃掉,不打印
        executor.setThreadFactory(new MyThreadFactory(executor));
        executor.initialize();
        return executor;
    }
}
@RequiredArgsConstructor
class MyThreadFactory implements ThreadFactory {
    private final ThreadFactory oldThreadFactory;  // 原始对象
    private static final MyUncaughtExceptionHandler myUncaughtExceptionHandler = new MyUncaughtExceptionHandler();
    @Override
    public Thread newThread(Runnable r) {
        Thread thread = oldThreadFactory.newThread(r);  // 执行spring创建线程自己的逻辑
        // 设置异常处理  新增的功能
        thread.setUncaughtExceptionHandler(myUncaughtExceptionHandler);
        return thread;
    }
}
@Slf4j
class MyUncaughtExceptionHandler implements Thread.UncaughtExceptionHandler {
    @Override
    public void uncaughtException(Thread t, Throwable e) {
        log.error("Exception in thread {} ", t.getName(), e);
    }
}


